package com.animatron.sample.client.tree.draw;

import java.util.ArrayList;
import java.util.List;

import com.animatron.sample.client.tree.node.Node;
import com.animatron.sample.client.tree.node.NodeHitKind;
import com.animatron.sample.client.tree.node.NodeHitResult;
import com.google.gwt.canvas.dom.client.Context2d;

public class TreeDrawer
{
	Context2d context2d;
	Node root;
	Node selected;
	int fontSize;
	double plusMinusWidth;
	double vOffset;
	static final int LEFT_MARGIN = 5;
	List<NodeLocation> nodesLocations = new ArrayList<TreeDrawer.NodeLocation>();

	private class NodeLocation
	{
		double left;
		double top;
		double width;
		double height;
		Node node;

		boolean isPlusMinus(double x)
		{
			return x < left + plusMinusWidth;
		}

		boolean hasPoint(double x, double y)
		{
			if (x >= left && x <= left + width)
				if (y >= top && y < top + height)
					return true;
			return false;
		}

		public NodeLocation(double left, double top, double width, double height, Node node)
		{
			super();
			this.left = left;
			this.top = top;
			this.width = width;
			this.height = height;
			this.node = node;
		}

	}

	private void repaintNode(Node node, int level)
	{
		repaintSingleNode(node, level);
		if (!node.isCollapsed())
			for (Node child : node.getItems())
				repaintNode(child, level + 1);
	}

	private void repaintSingleNode(Node node, int level)
	{
		double hOffset = LEFT_MARGIN + level * fontSize;
		// draw +/-
		if (node.getItems().size() > 0)
		{
			String plusMinus = node.isCollapsed() ? "+" : "-";
			context2d.fillText(plusMinus, hOffset, vOffset);
		}
		// draw text
		double textWidth = context2d.measureText(node.getName()).getWidth();
		if (node == selected)
		{
			context2d.save();
			context2d.setFillStyle("yellow");
			context2d.fillRect(hOffset + plusMinusWidth-1, vOffset, textWidth+1, fontSize+1);
			context2d.restore();
		}
		context2d.fillText(node.getName(), hOffset + plusMinusWidth, vOffset);
		nodesLocations.add(new NodeLocation(hOffset, vOffset, plusMinusWidth + textWidth, fontSize, node));
		vOffset += fontSize;
	}

	public TreeDrawer(Context2d context2d, Node root, Node selected, int fontSize)
	{
		super();
		this.context2d = context2d;
		this.root = root;
		this.selected = selected;
		this.fontSize = fontSize;
	}

	public void draw()
	{
		context2d.setFillStyle("black");
		context2d.setFont(fontSize + "px black");
		context2d.setTextBaseline("top");
		plusMinusWidth = context2d.measureText("+").getWidth()+2;
		vOffset = 5;
		nodesLocations.clear();
		repaintNode(root, 0);
	}
	
	public NodeHitResult nodeAt(double x, double y)
	{
		for(NodeLocation location : nodesLocations)
			if (location.hasPoint(x, y))
			{
				if (location.isPlusMinus(x))				
					return new NodeHitResult(NodeHitKind.PLUSMINUS, location.node);
				else
					return new NodeHitResult(NodeHitKind.CAPTION, location.node);
			}
		return new NodeHitResult(NodeHitKind.EMPTY, null);
	}
}
